package cn.smile.business.basic.impl;

import cn.smile.bean.dto.basic.MemberInfoDTO;
import cn.smile.bean.dto.basic.MyShopDTO;
import cn.smile.bean.entity.basic.MemberInfo;
import cn.smile.bean.form.basic.bill.TopUpAddForm;
import cn.smile.bean.form.basic.member.MemberAddForm;
import cn.smile.bean.form.basic.member.MemberUpdateForm;
import cn.smile.bean.form.basic.member.QueryMemberForm;
import cn.smile.bean.form.basic.member.UpdateBalanceForm;
import cn.smile.business.basic.IMemberService;
import cn.smile.business.basic.IMyShopService;
import cn.smile.business.basic.ITopUpBillService;
import cn.smile.business.basic.IVoucherMemberService;
import cn.smile.commons.constant.CommonConstant;
import cn.smile.commons.constant.MemberConstant;
import cn.smile.commons.constant.NumberConstant;
import cn.smile.commons.domain.BaseServiceImpl;
import cn.smile.commons.enums.basic.BalanceOperateEnum;
import cn.smile.commons.enums.basic.MemberStatusEnum;
import cn.smile.commons.exceptions.BusinessException;
import cn.smile.commons.response.MyResponseCode;
import cn.smile.repository.basic.MemberMapper;
import cn.smile.utils.BeanCopy;
import cn.smile.utils.DateFormatUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import jakarta.annotation.Resource;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class MemberServiceImpl extends BaseServiceImpl<MemberMapper, MemberInfo> implements IMemberService {

    @Resource
    private IMyShopService shopService;
    @Resource
    private ITopUpBillService topUpBillService;
    @Resource
    private IVoucherMemberService vouMemService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addInfo(MemberAddForm form) {
        log.info("[MemberServiceImpl].[addInfo] ------> 新增会员信息 Start, form = {}", JSON.toJSONString(form));
        Boolean flag = this.checkNo(form.getMemberNo(), null);
        if (flag) {
            throw new BusinessException(MyResponseCode.MEMBER_NO_EXIST_ERROR);
        }
        MemberInfo entity = BeanCopy.copyBean(form, MemberInfo.class);
        entity.setShopId(shopService.getMyShop().getId());
        entity.setStatus(MemberStatusEnum.ENABLE.getSn());
        //新增用户默认金额0.00元
        entity.setBalance(MemberConstant.DEFAULT_BALANCE);
        entity.setGiftBalance(MemberConstant.DEFAULT_BALANCE);
        super.addBaseCol(entity);
        int insertNum = baseMapper.insert(entity);
        if (insertNum > NumberConstant.ZERO && !ObjectUtils.isEmpty(form.getFirstPreStoreAmount())) {
            TopUpAddForm addForm = new TopUpAddForm();
            addForm.setMemberId(entity.getId());
            addForm.setFirstPreStore(Boolean.TRUE);
            addForm.setTopUpPrice(form.getFirstPreStoreAmount());
            addForm.setGiftPrice(form.getGiftPrice());
            addForm.setVoucherList(form.getVoucherList());
            topUpBillService.addTopUp(addForm);
        }
        log.info("[MemberServiceImpl].[addInfo] ------> 新增会员信息 End, insertNum = {}", insertNum);
        return insertNum > NumberConstant.ZERO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateInfo(MemberUpdateForm form) {
        log.info("[MemberServiceImpl].[updateInfo] ------> 更新会员信息 Start, form = {}", JSON.toJSONString(form));
        Boolean flag = this.checkNo(form.getMemberNo(), form.getId());
        if (flag) {
            throw new BusinessException(MyResponseCode.MEMBER_NO_EXIST_ERROR);
        }
        MemberInfo entity = baseMapper.selectOne(new QueryWrapper<MemberInfo>().lambda().eq(MemberInfo::getDeleted, Boolean.FALSE).eq(MemberInfo::getId, form.getId()));
        entity.setMemberNo(form.getMemberNo());
        entity.setMemberName(form.getMemberName());
        entity.setMemberPhone(form.getMemberPhone());
        entity.setDiscount(form.getDiscount());
        super.updateBaseCol(entity);
        int updateNum = baseMapper.updateById(entity);
        log.info("[MemberServiceImpl].[updateInfo] ------> 更新会员信息 End, updateNum = {}", updateNum);
        return updateNum > NumberConstant.ZERO;
    }

    @Override
    public Boolean checkNo(String memberNo, String id) {
        log.info("[MemberServiceImpl].[checkNo] ------> 检查会员号是否存在 Start, memberNo:{}, id:{}", memberNo, id);
        MyShopDTO myShop = shopService.getMyShop();
        LambdaQueryWrapper<MemberInfo> qw = new QueryWrapper<MemberInfo>().lambda().eq(MemberInfo::getDeleted, Boolean.FALSE);
        qw.eq(MemberInfo::getMemberNo, memberNo);
        qw.eq(MemberInfo::getShopId, myShop.getId());
        if (!ObjectUtils.isEmpty(id)) {
            qw.ne(MemberInfo::getId, id);
        }
        List<MemberInfo> dataList = baseMapper.selectList(qw);
        boolean flag;
        if (CollectionUtils.isEmpty(dataList)) {
            flag = Boolean.FALSE;
        } else {
            flag = Boolean.TRUE;
        }
        log.info("[MemberServiceImpl].[checkNo] ------> 检查会员号是否存在 Start, flag:{}", flag);
        return flag;
    }

    @Override
    public IPage<MemberInfoDTO> getMemberPage(QueryMemberForm form) {
        log.info("[MemberServiceImpl].[getMemberPage] ------> 分页查询店铺会员列表 Start, form = {}", JSON.toJSONString(form));
        LambdaQueryWrapper<MemberInfo> qw = this.getQueryParams(form);
        Page<MemberInfo> basePage = baseMapper.selectPage(form.queryPage(), qw);
        IPage<MemberInfoDTO> dataPage = BeanCopy.copyPage(basePage, MemberInfoDTO.class);
        this.setDetail(dataPage.getRecords());
        log.info("[MemberServiceImpl].[getMemberPage] ------> 分页查询店铺会员列表 End");
        return dataPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delMember(String id) {
        log.info("[MemberServiceImpl].[delMember] ------> 删除店铺会员 Start, id = {}", id);
        MemberInfo entity = this.getBaseById(id);
        if (MemberConstant.DEFAULT_BALANCE.compareTo(entity.getBalance()) < NumberConstant.ZERO) {
            throw new BusinessException(MyResponseCode.MEMBER_BALANCE_NOT_NULL_ERROR);
        }
        super.delBaseCol(entity);
        int updateNum = baseMapper.updateById(entity);
        log.info("[MemberServiceImpl].[delMember] ------> 删除店铺会员 End, updateNum = {}", updateNum);
        return updateNum > NumberConstant.ZERO;
    }

    @Override
    public MemberInfoDTO getMemberById(String id) {
        log.info("[MemberServiceImpl].[getMemberById] ------> 根据会员ID查询会员信息 Start, id = {}", id);
        MemberInfo entity = this.getBaseById(id);
        MemberInfoDTO dto = BeanCopy.copyBean(entity, MemberInfoDTO.class);
        this.setDetail(Lists.newArrayList(dto));
        log.info("[MemberServiceImpl].[getMemberById] ------> 根据会员ID查询会员信息 End");
        return dto;
    }

    @Override
    public MemberInfoDTO getBaseMemberById(String id) {
        log.info("[MemberServiceImpl].[getBaseMemberById] ------> 根据会员ID查询会员基础信息 Start, id = {}", id);
        MemberInfo entity = this.getBaseById(id);
        MemberInfoDTO dto = BeanCopy.copyBean(entity, MemberInfoDTO.class);
        log.info("[MemberServiceImpl].[getBaseMemberById] ------> 根据会员ID查询会员基础信息 End");
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BigDecimal updateBalance(UpdateBalanceForm form, BalanceOperateEnum operateEnum) {
        log.info("[MemberServiceImpl].[updateBalance] ------> 账户余额更新 Start, form = {}, operateEnum = {}", JSON.toJSONString(form), operateEnum);
        MemberInfoDTO entity = this.getBaseMemberById(form.getMemberId());
        boolean isUpdate = Boolean.FALSE;
        int oldVersion = entity.getVersion();
        BigDecimal expenseAmount = CommonConstant.DEFAULT_PRICE;
        switch (operateEnum) {
            case TOP_UP:
                //会员充值操作
                isUpdate = Boolean.TRUE;
                entity.setBalance(this.handBigDecimal(entity.getBalance()).add(this.handBigDecimal(form.getAmount())));
                entity.setGiftBalance(this.handBigDecimal(entity.getGiftBalance()).add(this.handBigDecimal(form.getGiftPrice())));
                break;
            case EXPENSE:
                //会员消费操作
                expenseAmount = this.setExpenseBalance(entity, form);
                isUpdate = Boolean.TRUE;
                break;
            default:
        }
        if (isUpdate) {
            //更新数据版本
            entity.setVersion(entity.getVersion() + NumberConstant.ONE);
            int updateNum = baseMapper.update(entity, new QueryWrapper<MemberInfo>().lambda().eq(MemberInfo::getId, entity.getId()).eq(MemberInfo::getVersion, oldVersion));
            if (updateNum <= NumberConstant.ZERO) {
                return this.updateBalance(form, operateEnum);
            }
        }
        log.info("[MemberServiceImpl].[updateBalance] ------> 账户余额更新 End, 实际消费金额 = {}", expenseAmount.toString());
        return expenseAmount;
    }

    @Override
    public List<MemberInfoDTO> getMemberList(QueryMemberForm form) {
        log.info("[MemberServiceImpl].[getMemberList] ------> 查询会员列表 Start, form = {}", JSON.toJSONString(form));
        LambdaQueryWrapper<MemberInfo> qw = this.getQueryParams(form);
        List<MemberInfo> baseList = baseMapper.selectList(qw);
        List<MemberInfoDTO> dataList = BeanCopy.copyList(baseList, MemberInfoDTO.class);
        this.setDetail(dataList);
        log.info("[MemberServiceImpl].[getMemberList] ------> 查询会员列表 End");
        return dataList;
    }

    @Override
    public Long countMemberByShop() {
        return this.countMemberByShop(DateFormatUtil.parseDateToStr(new Date(), DateFormatUtil.DATE_TIME_FORMAT_1));
    }

    @Override
    public Long countMemberByShop(String date) {
        log.info("[MemberServiceImpl].[countMemberByShop] ------> 统计店铺会员数量 Start, date = {}", date);
        MyShopDTO shop = shopService.getMyShop();
        LambdaQueryWrapper<MemberInfo> qw = new QueryWrapper<MemberInfo>().lambda().eq(MemberInfo::getDeleted, Boolean.FALSE);
        qw.eq(MemberInfo::getShopId, shop.getId());
        qw.le(MemberInfo::getCreateTime, date);
        Long memberNum = baseMapper.selectCount(qw);
        log.info("[MemberServiceImpl].[countMemberByShop] ------> 统计店铺会员数量 End, memberNum = {}", memberNum);
        return memberNum;
    }

    @Override
    public Long countAddMemberNum(String timeStart, String timeEnd) {
        log.info("[MemberServiceImpl].[countAddMemberNum] ------> 统计指定日期新增会员数量 Start, timeStart = {}, timeEnd = {}", timeStart, timeEnd);
        MyShopDTO shop = shopService.getMyShop();
        LambdaQueryWrapper<MemberInfo> qw = new QueryWrapper<MemberInfo>().lambda().eq(MemberInfo::getDeleted, Boolean.FALSE);
        qw.eq(MemberInfo::getShopId, shop.getId());
        qw.ge(MemberInfo::getCreateTime, timeStart);
        qw.le(MemberInfo::getCreateTime, timeEnd);
        Long memberNum = baseMapper.selectCount(qw);
        log.info("[MemberServiceImpl].[countAddMemberNum] ------> 统计指定日期新增会员数量 End, memberNum = {}", memberNum);
        return memberNum;
    }

    /**
     * BigDecimal 空处理
     *
     * @param value 获取到的属性
     * @return 处理之后的值
     */
    private BigDecimal handBigDecimal(BigDecimal value) {
        BigDecimal handValue;
        if (ObjectUtils.isEmpty(value)) {
            handValue = MemberConstant.DEFAULT_BALANCE;
        } else {
            handValue = value;
        }
        return handValue;
    }

    /**
     * 写入消费余额
     *
     * @param entity 会员对象
     * @param form   消费参数
     * @return 实际消费金额
     */
    private BigDecimal setExpenseBalance(MemberInfoDTO entity, UpdateBalanceForm form) {
        //充值金额
        BigDecimal expenseAmount = this.handBigDecimal(form.getAmount());
        BigDecimal balance = this.handBigDecimal(entity.getBalance());
        if (balance.compareTo(expenseAmount) < NumberConstant.ZERO) {
            throw new BusinessException(MyResponseCode.INSUFFICIENT_BALANCE_ERROR);
        }
        entity.setBalance(balance.subtract(expenseAmount));
        //赠送金额
        BigDecimal giftPrice = this.handBigDecimal(form.getGiftPrice());
        if (!ObjectUtils.isEmpty(giftPrice)) {
            BigDecimal giftBalance = this.handBigDecimal(entity.getGiftBalance());
            if (giftBalance.compareTo(giftPrice) < NumberConstant.ZERO) {
                throw new BusinessException(MyResponseCode.INSUFFICIENT_GIFT_BALANCE_ERROR);
            }
            entity.setGiftBalance(giftBalance.subtract(giftPrice));
        }

        return expenseAmount;
    }

    /**
     * 根据ID查询基本信息
     *
     * @param id 数据ID
     * @return 查询结果对象
     */
    private MemberInfo getBaseById(String id) {
        if (ObjectUtils.isEmpty(id)) {
            throw new BusinessException(MyResponseCode.MEMBER_ID_NULL_ERROR);
        }
        MemberInfo entity = baseMapper.selectOne(new QueryWrapper<MemberInfo>().lambda().eq(MemberInfo::getDeleted, Boolean.FALSE).eq(MemberInfo::getId, id));
        if (ObjectUtils.isEmpty(entity)) {
            throw new BusinessException(MyResponseCode.RESULT_DATA_NONE);
        }
        return entity;
    }

    /**
     * 写入详细信息
     *
     * @param dataList 数据集合
     */
    private void setDetail(List<MemberInfoDTO> dataList) {
        if (!CollectionUtils.isEmpty(dataList)) {
            List<String> ids = Lists.newArrayList();
            dataList.forEach(entity -> ids.add(entity.getId()));
            Map<String, Integer> coucherNumMap = vouMemService.countNumByMember(ids);
            for (MemberInfoDTO entity : dataList) {
                entity.setStatusText(MemberStatusEnum.get(entity.getStatus()).getMsg());
                entity.setVoucherNum(coucherNumMap.getOrDefault(entity.getId(), NumberConstant.ZERO));
            }
        }
    }

    /**
     * 组装查询参数对象
     *
     * @param form 查询参数
     * @return 数据库查询对象
     */
    private LambdaQueryWrapper<MemberInfo> getQueryParams(QueryMemberForm form) {
        LambdaQueryWrapper<MemberInfo> qw = new QueryWrapper<MemberInfo>().lambda().eq(MemberInfo::getDeleted, Boolean.FALSE);
        MyShopDTO myShop = shopService.getMyShop();
        qw.eq(MemberInfo::getShopId, myShop.getId());
        if (!ObjectUtils.isEmpty(form.getNameOrNo())) {
            qw.and(i -> i.like(MemberInfo::getMemberName, form.getNameOrNo()).or().like(MemberInfo::getMemberNo, form.getNameOrNo()).or().like(MemberInfo::getMemberPhone, form.getNameOrNo()));
        }
        if (!CollectionUtils.isEmpty(form.getIds())) {
            qw.in(MemberInfo::getId, form.getIds());
        }
        if (!ObjectUtils.isEmpty(form.getCreateTimeStart())) {
            qw.ge(MemberInfo::getCreateTime, form.getCreateTimeStart());
        }
        if (!ObjectUtils.isEmpty(form.getCreateTimeEnd())) {
            qw.le(MemberInfo::getCreateTime, form.getCreateTimeEnd());
        }
        return qw;
    }
}
